package com.maimang.platform.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.maimang.platform.lang.StringUtils;
import com.maimang.platform.shiro.cache.RedisCacheManager;
import com.maimang.platform.shiro.filter.MyFormAuthenticationFilter;
import com.maimang.platform.shiro.realm.AuthenticationFilter;
import com.maimang.platform.shiro.realm.UserRealm;
import com.maimang.platform.shiro.session.OnlineSessionFactory;
import com.maimang.platform.shiro.session.RedisSessionDAO;
import com.maimang.platform.shiro.session.OnlineSessionDAO;
import com.maimang.platform.shiro.web.filter.LogoutFilter;
import com.maimang.platform.shiro.web.filter.captcha.CaptchaValidateFilter;
import com.maimang.platform.shiro.web.filter.online.OnlineSessionFilter;
import com.maimang.platform.shiro.web.filter.sync.SyncOnlineSessionFilter;
import com.maimang.platform.shiro.web.session.OnlineWebSessionManager;
import com.maimang.platform.shiro.web.session.SpringSessionValidationScheduler;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilter;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 权限配置加载
 *
 * @author Rocky
 */
@Configuration
public class ShiroConfig {
	public static final String PREMISSION_STRING = "perms[\"{0}\"]";

	// Session超时时间，单位为毫秒（默认30分钟）
	@Value("${shiro.session.expireTime}")
	private int expireTime;

	// 相隔多久检查一次session的有效性，单位毫秒，默认就是10分钟
	@Value("${shiro.session.validationInterval}")
	private int validationInterval;

	// 验证码开关
	@Value("${shiro.user.captchaEnabled}")
	private boolean captchaEnabled;

	// 验证码类型
	@Value("${shiro.user.captchaType}")
	private String captchaType;

	// 设置Cookie的域名
	@Value("${shiro.cookie.domain}")
	private String domain;

	// 设置cookie的有效访问路径
	@Value("${shiro.cookie.path}")
	private String path;

	// 设置HttpOnly属性
	@Value("${shiro.cookie.httpOnly}")
	private boolean httpOnly;

	// 设置Cookie的过期时间，秒为单位
	@Value("${shiro.cookie.maxAge}")
	private int maxAge;

	// 登录地址
	@Value("${shiro.user.loginUrl}")
	private String loginUrl;

	//  登录成功地址
	@Value("${shiro.user.successUrl}")
	private String successUrl;

	// 权限认证失败地址
	@Value("${shiro.user.unauthorizedUrl}")
	private String unauthorizedUrl;

	// redis缓存开关
	@Value("${spring.redis.enabled}")
	private boolean redisEnabled = false;

	/**
	 * 缓存管理器 使用Ehcache实现
	 */
	@Bean
	public EhCacheManager getEhCacheManager() {
		net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("platform");
		EhCacheManager em = new EhCacheManager();
		if (StringUtils.isNull(cacheManager)) {
			em.setCacheManagerConfigFile("classpath:ehcache/ehcache.xml");
			return em;
		} else {
			em.setCacheManager(cacheManager);
			return em;
		}
	}

	/**
	 * 缓存管理器 使用redis实现
	 */
//    @Bean
//    @ConditionalOnMissingBean(name = "redisTemplate")
	public RedisCacheManager getRedisCacheManager() {
		RedisCacheManager redisCacheManager = new RedisCacheManager();
		return redisCacheManager;
	}

	/**
	 * 自定义Realm
	 */
	@Bean
	public UserRealm userRealm(CacheManager cacheManager) {
		UserRealm userRealm = new UserRealm();
		userRealm.setCacheManager(cacheManager);
		return userRealm;
	}

	/**
	 * 自定义sessionDAO会话
	 */
	@Bean
	public OnlineSessionDAO sessionDAO() {
		OnlineSessionDAO sessionDAO = new OnlineSessionDAO();
		return sessionDAO;
	}

	/**
	 * 自定义RedisSessionDAO会话
	 */
	@Bean
//    @ConditionalOnMissingBean(name = "redisTemplate")
	public RedisSessionDAO redisSessionDAO() {
		RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
		redisSessionDAO.setExpireTime(expireTime * 60);
		return redisSessionDAO;
	}

	/**
	 * 自定义sessionFactory会话
	 */
	@Bean
	public OnlineSessionFactory sessionFactory() {
		OnlineSessionFactory sessionFactory = new OnlineSessionFactory();
		return sessionFactory;
	}

	/**
	 * 自定义sessionFactory调度器
	 */
	@Bean
	public SpringSessionValidationScheduler sessionValidationScheduler() {
		SpringSessionValidationScheduler sessionValidationScheduler = new SpringSessionValidationScheduler();
		// 相隔多久检查一次session的有效性，单位毫秒，默认就是10分钟
		sessionValidationScheduler.setSessionValidationInterval(validationInterval * 60 * 1000);
		// 设置会话验证调度器进行会话验证时的会话管理器
		sessionValidationScheduler.setSessionManager(sessionValidationManager());
		return sessionValidationScheduler;
	}

	/**
	 * 会话管理器
	 */
	@Bean
	public OnlineWebSessionManager sessionValidationManager() {
		OnlineWebSessionManager manager = new OnlineWebSessionManager();
		// 加入缓存管理器
		manager.setCacheManager(redisEnabled ? getRedisCacheManager() : getEhCacheManager());
		// 删除过期的session
		manager.setDeleteInvalidSessions(true);
		// 设置全局session超时时间
		manager.setGlobalSessionTimeout(expireTime * 60 * 1000);
		// 去掉 JSESSIONID
		manager.setSessionIdUrlRewritingEnabled(false);
		// 是否定时检查session
		manager.setSessionValidationSchedulerEnabled(true);
		// 自定义SessionDao
		manager.setSessionDAO(redisEnabled ? redisSessionDAO() : sessionDAO());
		// 自定义sessionFactory
		manager.setSessionFactory(sessionFactory());
		return manager;
	}

	/**
	 * 会话管理器
	 */
	@Bean
	public OnlineWebSessionManager sessionManager() {
		OnlineWebSessionManager manager = new OnlineWebSessionManager();
		// 加入缓存管理器
		manager.setCacheManager(redisEnabled ? getRedisCacheManager() : getEhCacheManager());
		// 删除过期的session
		manager.setDeleteInvalidSessions(true);
		// 设置全局session超时时间
		manager.setGlobalSessionTimeout(expireTime * 60 * 1000);
		// 去掉 JSESSIONID
		manager.setSessionIdUrlRewritingEnabled(false);
		// 定义要使用的无效的Session定时调度器
		manager.setSessionValidationScheduler(sessionValidationScheduler());
		// 是否定时检查session
		manager.setSessionValidationSchedulerEnabled(true);
		// 自定义SessionDao
		manager.setSessionDAO(sessionDAO());
		// 自定义sessionFactory
		manager.setSessionFactory(sessionFactory());
		return manager;
	}

	/**
	 * 安全管理器
	 */
	@Bean
	public SecurityManager securityManager(UserRealm userRealm) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 设置realm
		securityManager.setRealm(userRealm);
		// 记住我
		securityManager.setRememberMeManager(rememberMeManager());
		// 注入缓存管理器
		securityManager.setCacheManager(redisEnabled ? getRedisCacheManager() : getEhCacheManager());
		// session管理器
		securityManager.setSessionManager(sessionManager());
		return securityManager;
	}

	/**
	 * 退出过滤器
	 */
	public LogoutFilter logoutFilter() {
		LogoutFilter logoutFilter = new LogoutFilter();
		logoutFilter.setLoginUrl(loginUrl);
		return logoutFilter;
	}

	/**
	 * Shiro过滤器配置
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// Shiro的核心安全接口,这个属性是必须的
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 身份认证失败，则跳转到登录页面的配置
		shiroFilterFactoryBean.setLoginUrl(loginUrl);
		// 身份认证成功，则跳转到首页页面的配置
		shiroFilterFactoryBean.setSuccessUrl(successUrl);
		// 权限认证失败，则跳转到指定页面
		shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);

		Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();
		// 直接创建对象，不使用Spring Bean 的方式
		filterMap.put("authc", new MyFormAuthenticationFilter());

		// Shiro连接约束配置，即过滤链的定义
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		// 对静态资源设置匿名访问
		filterChainDefinitionMap.put("/favicon.ico**", "anon");
		filterChainDefinitionMap.put("/platform.png**", "anon");
		filterChainDefinitionMap.put("/css/**", "anon");
		filterChainDefinitionMap.put("/docs/**", "anon");
		filterChainDefinitionMap.put("/fonts/**", "anon");
		filterChainDefinitionMap.put("/images/**", "anon");
		filterChainDefinitionMap.put("/ajax/**", "anon");
		filterChainDefinitionMap.put("/js/**", "anon");
		filterChainDefinitionMap.put("/test/**", "anon");
		filterChainDefinitionMap.put("/platform/**", "anon");
		filterChainDefinitionMap.put("/druid/**", "anon");
		filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
		filterChainDefinitionMap.put("/open/**", "anon"); // 不需要权限对外开放的接口
		filterChainDefinitionMap.put("/crm/**", "anon"); // jwt权限接口，拦截器处理WebConfig类
		filterChainDefinitionMap.put("/dingtalk/**", "anon"); // jwt权限接口，拦截器处理WebConfig类
		// 退出 logout地址，shiro去清除session
		filterChainDefinitionMap.put("/logout", "logout");
		// 不需要拦截的访问
		filterChainDefinitionMap.put("/login", "anon,captchaValidate");
		// 系统权限列表
		// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());

		filterChainDefinitionMap.put("/**", "authc");

		Map<String, Filter> filters = new LinkedHashMap<>();
		filters.put("onlineSession", onlineSessionFilter());
		filters.put("syncOnlineSession", syncOnlineSessionFilter());
		filters.put("captchaValidate", captchaValidateFilter());
		// 注销成功，则跳转到指定页面
		filters.put("logout", logoutFilter());
		// 自定义鉴权过滤器，添加无密登录
		filters.put("authentication", authenticationFilter());
		filters.put("authc", myFormAuthenticationFilter());
		shiroFilterFactoryBean.setFilters(filters);

		// 所有请求需要认证
		filterChainDefinitionMap.put("/**", "user,onlineSession,syncOnlineSession");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

		return shiroFilterFactoryBean;
	}

	/**
	 * 自定义在线用户处理过滤器
	 */
	@Bean
	public OnlineSessionFilter onlineSessionFilter() {
		OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter();
		onlineSessionFilter.setLoginUrl(loginUrl);
		return onlineSessionFilter;
	}

	/**
	 * 自定义在线用户同步过滤器
	 */
	@Bean
	public SyncOnlineSessionFilter syncOnlineSessionFilter() {
		SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter();
		return syncOnlineSessionFilter;
	}

	/**
	 * 自定义用户登录鉴权过滤器
	 * @return
	 */
	// @Bean
	public AuthenticationFilter authenticationFilter() {
		AuthenticationFilter authenticationFilter = new AuthenticationFilter();
		return authenticationFilter;
	}

	/**
	 * 自定义登录完成跳转过滤器
	 * @return
	 */
	@Bean
	public MyFormAuthenticationFilter myFormAuthenticationFilter() {
		MyFormAuthenticationFilter myFormAuthenticationFilter = new MyFormAuthenticationFilter();
		return myFormAuthenticationFilter;
	}

	/**
	 * 自定义验证码过滤器
	 */
	@Bean
	public CaptchaValidateFilter captchaValidateFilter() {
		CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter();
		captchaValidateFilter.setCaptchaEnabled(captchaEnabled);
		captchaValidateFilter.setCaptchaType(captchaType);
		return captchaValidateFilter;
	}

	/**
	 * cookie 属性设置
	 */
	public SimpleCookie rememberMeCookie() {
		SimpleCookie cookie = new SimpleCookie("rememberMe");
		cookie.setDomain(domain);
		cookie.setPath(path);
		cookie.setHttpOnly(httpOnly);
		cookie.setMaxAge(maxAge * 24 * 60 * 60);
		return cookie;
	}

	/**
	 * 记住我
	 */
	public CookieRememberMeManager rememberMeManager() {
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCookie(rememberMeCookie());
		cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ=="));
		return cookieRememberMeManager;
	}

	/**
	 * thymeleaf模板引擎和shiro框架的整合
	 */
	@Bean
	public ShiroDialect shiroDialect() {
		return new ShiroDialect();
	}

	/**
	 * 开启Shiro注解通知器
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
}
